package com.oracle.coherence.patterns.security.proxy;

import com.oracle.coherence.patterns.security.KrbSecurityHelper;
import com.oracle.coherence.patterns.security.extend.ExtendAccessController;
import com.oracle.coherence.patterns.security.extend.InvocationPermission;
import com.oracle.coherence.patterns.security.extend.InvokeAction;
import com.tangosol.coherence.Component;
import com.tangosol.coherence.component.net.extend.proxy.InvocationServiceProxy;
import com.tangosol.net.Invocable;
import com.tangosol.net.InvocationObserver;

import java.util.Map;
import java.util.Set;

/**
 * This class is an extension of the Coherence {@link InvocationServiceProxy}.
 * <p/>
 * This implmentation overrides the <code>ensureNamedCacheProxy</code> method
 * and checks that the Security principal is authorised to access the
 * requested cache by calling the configured {@link ExtendAccessController}.
 * <p/>
 * @author Jonathan Knight
 */

/**
 * @author Jonathan Knight
 */
public class SecureInvocationServiceProxy extends InvocationServiceProxy {

    private ExtendAccessController accessController;

    /**
     * Default empty constructor
     */
    public SecureInvocationServiceProxy() {
    }

    /**
     * A constructor that sets the {@link com.oracle.coherence.patterns.security.extend.ExtendAccessController}
     * that this SecureInvocationServiceProxy will use to authorise access to Extend caches.
     * <p/>
     *
     * @param accessController - the {@link com.oracle.coherence.patterns.security.extend.ExtendAccessController} to use
     */
    public SecureInvocationServiceProxy(ExtendAccessController accessController) {
        this.accessController = accessController;
    }

    @Override
    public void execute(Invocable invocable, Set set, InvocationObserver invocationObserver) {
        if (accessController != null) {
            InvocationPermission permission = new InvocationPermission(getName(), InvokeAction.EXECUTE.toString());
            accessController.checkPermission(permission, KrbSecurityHelper.getCurrentSubject());
        }
        super.execute(invocable, set, invocationObserver);
    }

    /**
     * Checks that the current security principal is authorised to
     * perform a query operation on the Invocation Service prior
     * to calling the super class <code>query</code> method.
     *
     * @param invocable - the Invocable object to be invoked
     * @return a Map of result objects
     */
    @Override
    public Object query(Invocable invocable) {
        if (accessController != null) {
            InvocationPermission permission = new InvocationPermission(getName(), InvokeAction.QUERY.toString());
            accessController.checkPermission(permission, KrbSecurityHelper.getCurrentSubject());
        }
        return super.query(invocable);
    }

    /**
     * Checks that the current security principal is authorised to
     * perform a query operation on the Invocation Service prior
     * to calling the super class <code>query</code> method.
     *
     * @param invocable - the Invocable object to be invoked
     * @return a Map of result objects
     */
    @Override
    public Map query(Invocable invocable, Set set) {
        if (accessController != null) {
            InvocationPermission permission = new InvocationPermission(getName(), InvokeAction.QUERY.toString());
            accessController.checkPermission(permission, KrbSecurityHelper.getCurrentSubject());
        }
        return super.query(invocable, set);
    }

    /**
     * All Coherence Compaonent classes appear to implement this method.<p/>
     *
     * @return the class of this class.
     */
    public static Class get_CLASS() {
        return SecureInvocationServiceProxy.class;
    }

    /**
     * All Coherence Compaonent classes appear to implement this method.<p/>
     *
     * @return a new instance of SecureProxyService.
     */
    public static Component get_Instance() {
        return new SecureInvocationServiceProxy();
    }
}
